////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "WNFileSystem/inc/WNWriteFileBuffer.h"
#include "WNMemory/inc/WNAllocation.h"
#include "WNContainers/inc/WNSerializer.h"

using namespace WNFileSystem;
using namespace WNMemory;

WNWriteTextFileBuffer::WNWriteTextFileBuffer(WNFileBufferType _type, WN_SIZE_T _bufferSize) :
    WNFileBuffer(_type),
    mBufferUsage(0),
    mBufferSize(_bufferSize) {
    mCurrentBuffer = WNMallocT<WN_CHAR>(_bufferSize);

    WN_RELEASE_ASSERT(mCurrentBuffer != WN_NULL);
}

WNWriteTextFileBuffer::~WNWriteTextFileBuffer() {
    if (mFile.IsValid()) {
        DumpToFile();

        if (mCurrentBuffer != WN_NULL) {
            WNFreeT<WN_CHAR>(mCurrentBuffer);
        }
    }
}

WN_CHAR* WNWriteTextFileBuffer::ReserveBytes(WN_SIZE_T _numBytes, WN_SIZE_T& _returnedBytes) {
    if (_numBytes + mBufferUsage > mBufferSize) {
        if (mBufferUsage > 0) {
            if (!DumpToFile()) {
                WNFreeT<WN_CHAR>(mCurrentBuffer);

                _returnedBytes = 0;

                return(WN_NULL);
            }
        }

        if (_numBytes > mBufferSize) {
            mCurrentBuffer = WNReallocT<WN_CHAR>(mCurrentBuffer, _numBytes);

            WN_RELEASE_ASSERT(mCurrentBuffer != WN_NULL);

            mBufferUsage = 0;
            mBufferSize = _numBytes;
        }
    }

    _returnedBytes = _numBytes;

    return(mCurrentBuffer + mBufferUsage);
}

WN_BOOL WNWriteTextFileBuffer::DumpToFile() {
    if (!mFile.IsValid() || mBufferUsage == 0) {
        return(WN_FALSE);
    }

    const WN_SIZE_T written = mFile.WriteData(mCurrentBuffer, mBufferUsage);

    if (written != mBufferUsage) {
        return(WN_FALSE);
    }

    return(WN_TRUE);
}

WNContainers::WNDataBufferType WNWriteTextFileBuffer::GetType() {
    switch(mType) {
    case WNFileBuffer::WNText:
        return(WNContainers::WriteText);
    case WNFileBuffer::WNBinary:
        return(WNContainers::WriteBinary);
    }

    mType = WNFileBuffer::WNText;

    return(WNContainers::WriteText);
}

WNFile::WNFileError WNWriteTextFileBuffer::SetFile(const WN_CHAR* _fileName) {
    WN_RELEASE_ASSERT_DESC(!mFile.IsValid(), "Error, trying to set a file on a text buffer that already exists");

    return(mFile.OpenFile(_fileName, WNFile::WN_CLOBBER | WNFile::WN_EXCLUSIVE |
                                     WNFile::WN_WRITE | WNFile::WN_CREATE | WNFile::WN_STREAM));
}

WN_BOOL WNWriteTextFileBuffer::Serialize(WN_UINT32 _flags, const WNContainers::WNSerializerBase& _serializer) {
    mBufferUsage += _serializer.Serialize(*this, _flags);

    return(WN_TRUE);
}
